package com.ktwlsoft.archivemanage.service.security;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.ktwlsoft.archivemanage.domain.dao.entity.Account;
import com.ktwlsoft.archivemanage.domain.dao.repository.IUserRolesMapper;
import com.ktwlsoft.archivemanage.payload.exception.BusinessException;
import lombok.Getter;
import lombok.Setter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.Collection;
import java.util.List;
import java.util.Objects;

@Getter
@Setter
public class UserPrincipal implements UserDetails {

    private static final Logger logger = LoggerFactory.getLogger(UserPrincipal.class);

    private Long id;

    private String realName;

    //不能重命名
    private String username;

    @JsonIgnore
    private String email;

    @JsonIgnore
    private String password;

    private String profile;

    private Boolean sex;

    private String departmentName;

    private Long departmentId;

    private String teleNum;

    private String identityType;

    private String identityNum;

    private String remark;

    private String roleName;

    private Long roleId;

    private String introduce;

    private Collection<? extends GrantedAuthority> authorities;

    @Autowired
    private IUserRolesMapper userRolesMapper;

    public UserPrincipal(Long id, String realName, String username, String email, String password, String profile,
                         Boolean sex, String departmentName, Long departmentId, String teleNum, String identityType,
                         String identityNum, String remark, String roleName, Long roleId, String introduce,
                         Collection<? extends GrantedAuthority> authorities) {
        this.id = id;
        this.realName = realName;
        this.username = username;
        this.email = email;
        this.password = password;
        this.profile = profile;
        this.sex = sex;
        this.departmentName = departmentName;
        this.departmentId = departmentId;
        this.teleNum = teleNum;
        this.identityType = identityType;
        this.identityNum = identityNum;
        this.remark = remark;
        this.authorities = authorities;
        this.roleName = roleName;
        this.roleId = roleId;
        this.introduce = introduce;
    }

    public static UserPrincipal create(Account user, List<GrantedAuthority> authorities) {
//        List<GrantedAuthority> authorities = user.getRoles().stream().map(role ->
//                new SimpleGrantedAuthority(role.getName().name())
//        ).collect(Collectors.toList());

        return new UserPrincipal(
                user.getId(),
                user.getRealName(),
                user.getUserName(),
                user.getEmail(),
                user.getPassword(),
                user.getProfile(),
                user.getSex(),
                user.getDepartmentName(),
                user.getDepartmentId(),
                user.getTeleNum(),
                user.getIdentityType(),
                user.getIdentityNum(),
                user.getRemark(),
                user.getRoleName(),
                user.getRoleId(),
                user.getIntroduce(),
                authorities);
    }

    public static Account getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserPrincipal userPrincipal;
        try {
            userPrincipal = (UserPrincipal) authentication.getPrincipal();
            return new Account(
                    userPrincipal.getId(),
                    userPrincipal.getUsername(),
                    userPrincipal.getRealName(),
                    userPrincipal.getTeleNum(),
                    userPrincipal.getSex(),
                    userPrincipal.getEmail(),
                    userPrincipal.getRoleId(),
                    userPrincipal.getRoleName(),
                    userPrincipal.getDepartmentId(),
                    userPrincipal.getDepartmentName(),
                    userPrincipal.getIdentityType(),
                    userPrincipal.getIdentityNum(),
                    userPrincipal.getRemark(),
                    userPrincipal.getProfile(),
                    userPrincipal.getIntroduce()
            );
        } catch (Exception ex) {
            logger.error("强制转换Principal至UserPrincipal出错，消息：" + ex.getMessage());
        }
        try {
            logger.info("可能进入测试环境，正在解析用户权限中...");
            JSONObject jUser = (JSONObject) JSON.toJSON(authentication.getPrincipal());
            return new Account(jUser.getString("username"), "ADMIN");
        } catch (Exception ex) {
            logger.error("获取用户信息出错，消息：" + ex.getMessage());
            return null;
//            throw new BusinessException("获取用户信息出错，消息：" + ex.getMessage());
        }
    }

    @Override
    public String getUsername() {
        return username;
    }

    @Override
    public String getPassword() {
        return password;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserPrincipal that = (UserPrincipal) o;
        return Objects.equals(id, that.id);
    }

    @Override
    public int hashCode() {

        return Objects.hash(id);
    }
}
